#include <iostream>
#include <string>
#include<mutex>
using namespace std;

// 饿汉式单例模式，线程安全的
class HungrySingleton
{
public:
    // 因为其不能依赖对象，所以要定义成静态成员方法，获取类的唯一实例对象的方法
    static HungrySingleton* getSingleton()
    {
        return &instance;
    }
private:
    // 单例模式，不允许用户new对象，所以需要使用构造函数私有化
    HungrySingleton()
    {

    }
    static HungrySingleton instance;
    // 将拷贝构造函数和赋值操作符重载进行删除，使其不能完成对象创建，只能依赖getSingleton过去唯一的实例化对象
    HungrySingleton& operator=(const HungrySingleton &) = delete;
    HungrySingleton(const HungrySingleton &) = delete;
};
// 类内定义，类外初始化，更多static初始化查看 https://blog.csdn.net/sevenjoin/article/details/81772792
// 静态成员在数据段，在main函数之前就创建了，如果不使用的话，这个资源就浪费了
HungrySingleton HungrySingleton::instance;

mutex lazySingletonMtx;

// 懒汉式单例模式，线程安全的
class LazySingleton
{
public:
    // 因为其不能依赖对象，所以要定义成静态成员方法，获取类的唯一实例对象的方法
    // 可重入函数的概念？一个线程还没执行完，该函数被另一个线程执行
    static LazySingleton *getSingleton()
    {   
        if(instance==nullptr)
        {
            lock_guard<mutex> lck(lazySingletonMtx); // 所以多线程环境下需要加锁和双重判断
            /*
            不是线程安全，下面这个instance = new LazySingleton()需要执行-：开辟内存、构造对象、instance赋值
            */
            if(instance==nullptr)
            { 
                // 双重判断，防止两个线程同时进入上层的if判断中
                instance = new LazySingleton();
            }
        }
        return instance;
    }

private:
    // 单例模式，不允许用户new对象，所以需要使用构造函数私有化
    LazySingleton()
    {
    }
    static LazySingleton*volatile instance;
    // 将拷贝构造函数和赋值操作符重载进行删除，使其不能完成对象创建，只能依赖getSingleton过去唯一的实例化对象
    LazySingleton &operator=(const LazySingleton &) = delete;
    LazySingleton(const LazySingleton &) = delete;
};
// 类内定义，类外初始化，更多static初始化查看 https://blog.csdn.net/sevenjoin/article/details/81772792
// 静态成员在数据段，在main函数之前就创建了，如果不使用的话，这个资源就浪费了
LazySingleton*volatile LazySingleton::instance=nullptr;

// 懒汉式单例模式，线程安全的
class LazySingleton2
{
public:
    // 因为其不能依赖对象，所以要定义成静态成员方法，获取类的唯一实例对象的方法
    // 可重入函数的概念？一个线程还没执行完，该函数不能被另一个线程执行，也就是线程互斥
    static LazySingleton2 *getSingleton()
    {
        // 静态对象，运行到这个函数才开始初始化
        // 函数静态局部变量的初始化，在汇编指令上已经自动添加线程互斥指令
        static LazySingleton2 instance;
        return &instance;
    }

private:
    // 单例模式，不允许用户new对象，所以需要使用构造函数私有化
    LazySingleton2()
    {
    }
    // 将拷贝构造函数和赋值操作符重载进行删除，使其不能完成对象创建，只能依赖getSingleton过去唯一的实例化对象
    LazySingleton2 &operator=(const LazySingleton2 &) = delete;
    LazySingleton2(const LazySingleton2 &) = delete;
};


int main()
{
    HungrySingleton *p1 = HungrySingleton::getSingleton();
    HungrySingleton *p2 = HungrySingleton::getSingleton();
    HungrySingleton *p3 = HungrySingleton::getSingleton();
    cout << p1 << " " << p2 << " " << p3 << endl; // 0x407030 0x407030 0x407030

    LazySingleton *p4 = LazySingleton::getSingleton();
    LazySingleton *p5 = LazySingleton::getSingleton();
    LazySingleton *p6 = LazySingleton::getSingleton();
    cout << p4 << " " << p5 << " " << p6 << endl; // 0x25d2430 0x25d2430 0x25d2430

    // HungrySingleton t = *p1; // 拷贝构造函数私有化之后就不能完成拷贝构造了

    return 0;
}